"use strict";

class Watermark {
  #div = null;
  bg = null;
  constructor(el, options) {
    let _el = el;
    let _options = options;
    Object.defineProperty(this, "el", {
      configurable: false,
      get() {
        return _el ? document.querySelector(_el) : document.body;
      },
      set() {
        throw new Error(
          "Cannot assign to read only property 'el' of class 'Watermark'"
        );
      },
    });
    Object.defineProperty(this, "options", {
      configurable: false,
      get() {
        return {
          text: _options?.text ?? "Watermark",
          fontSize: _options?.fontSize ?? 40,
          gap: _options?.gap ?? 20,
        };
      },
      set() {
        throw new Error(
          "Cannot assign to read only property 'options' of class 'Watermark'"
        );
      },
    });
    Object.seal(this);
    this.#getWatermarkBg().then((res) => {
      this.bg = res;
      Object.defineProperty(this, "bg", {
        configurable: false,
        writable: false,
      });
      this.resetWatermark();
      this.#mutationObserver();
    });
  }
  /**
   * 重置水印
   */
  resetWatermark() {
    if (this.#div) {
      this.#div.remove();
    }
    this.#div = this.#getWatermarkDiv();
    this.el.appendChild(this.#div);
  }
  /**
   * 获取水印背景
   * @returns {Object} { base64: string, size: number }
   */
  #getWatermarkBg() {
    return new Promise((resolve, reject) => {
      const canvas = document.createElement("canvas");
      const ctx = canvas.getContext("2d");
      const devicePixelRatio = window.devicePixelRatio || 1;
      const fontSize = this.options.fontSize * devicePixelRatio;
      const font = `${fontSize}px serif`;

      ctx.font = font;
      const { width } = ctx.measureText(this.options.text);
      const canvasSize =
        Math.max(100, width) + this.options.gap * devicePixelRatio;
      canvas.width = canvasSize;
      canvas.height = canvasSize;

      ctx.translate(canvas.width / 2, canvas.height / 2);
      ctx.rotate(-Math.PI / 4);
      ctx.font = font;
      ctx.fillStyle = "rgba(0, 0, 0, 0.1)";
      ctx.textAlign = "center";
      ctx.textBaseline = "middle";
      ctx.fillText(this.options.text, 0, 0);
      canvas.toBlob((blob) => {
        resolve({
          blob: URL.createObjectURL(blob),
          size: canvasSize / devicePixelRatio,
        });
      });
    });
  }

  /**
   * 获取水印div
   * @returns {HTMLDivElement}
   */
  #getWatermarkDiv() {
    const { blob, size } = this.bg;
    const div = document.createElement("div");
    div.style.position = "absolute";
    div.style.backgroundImage = `url(${blob})`;
    div.style.backgroundRepeat = "repeat";
    div.style.backgroundSize = `${size}px ${size}px`;
    div.style.inset = 0;
    div.style.zIndex = 9999;
    div.style.pointerEvents = "none";
    return div;
  }

  /**
   * 监听DOM变化
   */
  #mutationObserver() {
    const observer = new MutationObserver((entries) => {
      entries.forEach((entry) => {
        // 处理删除的情况
        entry.removedNodes.forEach((node) => {
          if (node === this.#div) {
            this.resetWatermark();
          }
        });
        // 处理属性的变化
        if (entry.target === this.#div) {
          this.resetWatermark();
        }
      });
    });
    observer.observe(this.el, {
      childList: true, // 子节点的变化
      subtree: true, // 子节点及其后代节点的变化
      attributes: true, // 属性的变化
    });
  }
}
